package sep.test;

import static com.googlecode.javacv.cpp.opencv_core.CV_RGB;

import java.io.Serializable;

import com.googlecode.javacv.cpp.opencv_core.CvMat;
import com.googlecode.javacv.cpp.opencv_core.CvPoint2D32f;
import com.googlecode.javacv.cpp.opencv_core.CvScalar;
import com.googlecode.javacv.cpp.opencv_core.IplImage;

public abstract class IdaStreetModel implements Serializable {

	private static final long serialVersionUID = -6818091247807622835L;

	public enum StreetModelType {
		Simple, Polynom3
	}

	protected final static double INITIAL_WIDTH = 2.0;
	protected final static double MAX_STREET_LENGTH = 8.0;
	protected final static CvScalar LANE_COLOR = CV_RGB(255, 0, 0);
	protected final static int LANE_THICKNESS = 2;

	protected transient boolean initialized = false;
	protected transient IdaCameraModel cameraModel;
	protected transient CvMat matState;
	protected transient CvMat matObservation;
	protected transient CvMat matTransition;

	/**
	 * X Koordinaten der horizontalen Linien, mit denen das Strassenmodell
	 * geschnitten(abgetastet) wird
	 */
	protected transient volatile double[] scanlines;

	public void initialize(final IdaCameraModel cameraModel,
			final int noOfScanlines) {
		this.cameraModel = cameraModel;
		setNoOfScanlines(noOfScanlines);
		reset();
		initialized = true;
	}

	public abstract void drawLane(final IplImage image);

	public abstract void reset();

	public abstract double getIntersectionPoint(final int scanlineIdx,
			final boolean leftPoint);

	public abstract StreetModelType getStreetType();

	public void setStateMatrix(final CvMat state) {
		matState.put(state);
	}

	public CvMat getStateMatrix() {
		return matState;
	}

	public abstract CvMat getObservationMatrix(final boolean leftPoint,
			final int scanlineIdx);

	public int getNoOfScanlines() {
		if (scanlines != null)
			return scanlines.length;
		else
			return 0;
	}

	public void setNoOfScanlines(final int noOfScanlines) {
		if (noOfScanlines < 1) {
			throw new IllegalArgumentException(
					"Number of scanlines must be at least 1.");
		}

		// Scanlines erzeugen
		scanlines = new double[noOfScanlines];
		final double stepWidth = MAX_STREET_LENGTH / noOfScanlines;

		for (int i = 0; i < noOfScanlines; i++) {
			scanlines[i] = stepWidth * i;
		}
	}

	public double[] getProjectedScanlines() {
		if (scanlines == null) {
			throw new IllegalStateException(
					"Street model must be initialized first.");
		}

		final double[] projLines = new double[scanlines.length];
		CvPoint2D32f p;

		// Scanlines bzw. deren y-Koordinaten ins Bild projizieren
		for (int i = 0; i < scanlines.length; i++) {
			p = cameraModel.toCameraCoordinates(scanlines[i], 0.0, 0.0);
			projLines[i] = p.y();
		}

		return projLines;
	}

	public double[] getScanlines() {
		return scanlines;
	}

	public CvMat getTransitionMatrix() {
		return matTransition;
	}

	/**
	 * Daten und Strukturen erzeugen, die beim Laden nicht ber�cksichtigt werden
	 */
	public abstract void create();
}
